package org.pp.openapi.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.pp.openapi.common.ApiException;
import org.pp.openapi.consts.CacheKeys;
import org.pp.openapi.consts.LogType;
import org.pp.openapi.domain.*;
import org.pp.openapi.service.IApiLoaderService;
import org.pp.openapi.service.IDbService;
import org.pp.openapi.vo.SqlPager;
import org.pp.openapi.vo.TableQuery;
import org.pp.openapi.utils.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 自动加载启动资源
 */
@Service
@Slf4j
public class ApiLoaderServiceImpl implements IApiLoaderService {

    @Autowired
    private IDbService dbService;
    @Autowired
    private DataSource dataSource;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查询缓存
     * @param cacheKey
     * @param <T>
     * @return
     */
    @Override
    public <T> T getCacheObject(String cacheKey){
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(cacheKey);
    }

    /**
     * 设置缓存
     * @param cacheKey
     * @param cacheVal
     * @param <T>
     */
    @Override
    public <T> void setCacheObject(String cacheKey, T cacheVal){
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        operation.set(cacheKey, cacheVal);
    }

    /**
     * 清空指定前缀的缓存
     * @param cacheKeyPrefix
     */
    @Override
    public void removeCaches(String cacheKeyPrefix){
        Set<String> keys = redisTemplate.keys(cacheKeyPrefix+"**");
        if(keys == null || keys.isEmpty()){
            return;
        }else{
            redisTemplate.delete(keys);
        }
    }

    /**
     * 删除一个缓存
     * @param cacheKey
     */
    @Override
    public void removeCache(String cacheKey){
        redisTemplate.delete(cacheKey);
    }

    /**
     * 加载模型
     */
    @Override
    public int loadModel(){
        removeCaches(CacheKeys.CACHE_MODEL);
        List<Map> list = dbService.query("SELECT * FROM api_model");
        for(Map row:list){
            ApiModel model = ApiModel.fromMap(row);
            loadModel(model);
        }
        return list.size();
    }

    /**
     * 加载模型的字段和权限
     * @param model
     */
    public void loadModel(ApiModel model){
        log.debug("加载模型 {} : {}",  model.getCode(), model.getName());
        try {
            Connection connection = dataSource.getConnection();
            DatabaseMetaData dm = connection.getMetaData();
            ResultSet rs = dm.getColumns(null, null, model.getCode(), null);
            while(rs.next()){
                ApiField field = new ApiField();
                field.setModelId(model.getId());
                field.setCode(rs.getString("COLUMN_NAME"));
                field.setName(rs.getString("REMARKS"));
                field.setType(rs.getInt("DATA_TYPE"));
                field.setLength(rs.getInt("COLUMN_SIZE"));
                field.setScale(rs.getInt("DECIMAL_DIGITS"));
                field.setNullable(rs.getInt("NULLABLE") == 0);
                model.addField(field);
            }

            //权限
            List<Map> list = dbService.query("SELECT * FROM api_access WHERE model_id = "+model.getId());
            for(Map row:list){
                model.addAccess(ApiAccess.fromMap(row));
            }

            setCacheObject(CacheKeys.CACHE_MODEL + model.getCode(), model);
        }catch (SQLException e){
            e.printStackTrace();
        }
    }

    /**
     * 加载事件
     */
    @Override
    public int loadEvent(){
        removeCaches(CacheKeys.CACHE_EVENT);
        List<Map> list = dbService.query("SELECT * FROM api_event");
        for(Map row:list){
            ApiEvent event = ApiEvent.fromMap(row);
            setCacheObject(CacheKeys.CACHE_EVENT+event.getModelId()+"_"+event.getAction(), event);
        }
        return list.size();
    }

    /**
     * 加载内置SQL
     */
    @Override
    public int loadSql(){
        removeCaches(CacheKeys.CACHE_SQL);
        List<Map> list = dbService.query("SELECT * FROM api_sql");
        for(Map row:list){
            ApiSql sql = ApiSql.fromMap(row);
            setCacheObject(CacheKeys.CACHE_SQL+sql.getCode(), sql);
        }
        return list.size();
    }
    /**
     * 查询模型
     * @param table
     * @return
     */
    @Override
    public ApiModel getModel(String table){
        ApiModel model = getCacheObject(CacheKeys.CACHE_MODEL+table);
        dbService.log(null, LogType.ERROR.getCode(), null, "模型未定义 @"+table);
        return model;
    }

    /**
     * 查询模型事件
     * @param modelId
     * @param action
     * @return
     */
    @Override
    public ApiEvent getEvent(Long modelId, String action){
        return getCacheObject(CacheKeys.CACHE_EVENT+modelId+"_"+action);
    }

    /**
     * 查询内置脚本
     * @param code
     * @return
     */
    @Override
    public ApiSql getSql(String code){
        ApiSql sql =  getCacheObject(CacheKeys.CACHE_SQL+code);
        dbService.log(null, LogType.ERROR.getCode(), null, "脚本未定义 @"+code);
        return sql;
    }
    /**
     * 重置缓存
     * @param type 类型：model模型 event事件 sql内置脚本
     * @param ids 主键数组
     * @return
     */
    @Override
    public int reload(String type, Long[] ids){
        if("model".equalsIgnoreCase(type)){
            if(ids == null || ids.length == 0){
                return loadModel();
            }
            TableQuery table = new TableQuery();
            table.setTable("api_model");
            table.addData("id", StrUtil.join(ids, ","));
            table.setExp("id", "in");
            table.setPager(new SqlPager(1000,1));
            List<Map> list = dbService.query(table);
            for(Map row:list){
                ApiModel model = ApiModel.fromMap(row);
                loadModel(model);
            }
        }else if("event".equalsIgnoreCase(type)){
            if(ids == null || ids.length == 0){
                return loadEvent();
            }

            TableQuery table = new TableQuery();
            table.setTable("api_event");
            table.addData("id", StrUtil.join(ids, ","));
            table.setExp("id", "in");
            table.setPager(new SqlPager(1000,1));
            List<Map> list = dbService.query(table);
            for(Map row:list){
                ApiEvent event = ApiEvent.fromMap(row);
                setCacheObject(CacheKeys.CACHE_EVENT+event.getModelId()+"_"+event.getAction(), event);
            }
        }else if("sql".equalsIgnoreCase(type)){
            if(ids == null || ids.length == 0){
                return loadSql();
            }
            TableQuery table = new TableQuery();
            table.setTable("api_sql");
            table.addData("id", StrUtil.join(ids, ","));
            table.setExp("id", "in");
            table.setPager(new SqlPager(1000,1));
            List<Map> list = dbService.query(table);
            for(Map row:list){
                ApiSql sql = ApiSql.fromMap(row);
                setCacheObject(CacheKeys.CACHE_SQL+sql.getCode(), sql);
            }
        }else{
            throw new ApiException("不支持的操作");
        }
        return ids.length;
    }
}
